package com.ybbase.framework.service.flow.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ybbase.framework.base.model.ResponseBean;
import com.ybbase.framework.common.constant.CommonResultCode;
import com.ybbase.framework.common.util.ReflectionUtils;
import com.ybbase.framework.model.enumeration.FlowApproveOpinion;
import com.ybbase.framework.model.po.flow.ActionConfig;
import com.ybbase.framework.model.po.flow.FlowActionMethodParam;
import com.ybbase.framework.model.po.flow.InstanceRecord;
import com.ybbase.framework.model.po.system.User;
import com.ybbase.framework.model.vo.BusinessEntityVO;
import com.ybbase.framework.service.flow.ActionConfigService;
import com.ybbase.framework.service.flow.BaseFlowService;
import com.ybbase.framework.service.flow.BaseWeightService;
import com.ybbase.framework.service.flow.ProcessCoreService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author cg
 * @date 2019-10-18 17:27
 * @since 4.0
 */
@Service
public class BaseWeightServiceImpl implements BaseWeightService {

    private static final Logger logger = LogManager.getLogger(BaseWeightServiceImpl.class);
    private static final String COMMON_USER_STR = "userId";
    private static final String COMMON_USER_ID = "1";

    @Autowired
    ProcessCoreService processCoreService;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    TaskService taskService;
    @Autowired
    ActionConfigService actionConfigService;
    @Autowired
    BaseFlowService baseFlowService;

    /**
     * 通过提煤单号和煤矿编码查询煤种中带的流程编码
     *
     * @param collieryId 煤矿编码
     * @return
     * @author cg
     * @date 2019-09-24 19:55
     * @since 4.0
     */
    public String getBusinessCode(String collieryId) {
        return "";
    }

    /**
     * 通过业务代码和流程代码查询当前流程是否存在
     *
     * @param
     * @return
     * @author cg
     * @date 2019-09-24 20:57
     * @since 4.0
     */
    public ProcessInstance isFlowExist(String voucherId, String collieryCode, String flowCode) {
        ProcessInstance pi = null;
        String businessCode = voucherId + collieryCode;
        BusinessEntityVO businessEntityVO = new BusinessEntityVO();
        businessEntityVO.setBusinessId(businessCode);
        businessEntityVO.setFlowCode(flowCode);
        InstanceRecord in = processCoreService.getInstanceRecordByVO(businessEntityVO);
        if(in!=null){
            pi = runtimeService.createProcessInstanceQuery().processInstanceId(in.getRunProcessInstanceId()).singleResult();
        }
        return pi;
    }

    /**
     * 根据实例ID获取流程实例任务
     *
     * @param processInstanceId 流程实例ID
     * @return
     * @author cg
     * @date 2019-09-24 21:25
     * @since 4.0
     */
    public Task getTaskByProcessId(String processInstanceId) {
        Task task = taskService.createTaskQuery().processInstanceId
                (processInstanceId).active().singleResult();
        return task;
    }
    /**
     * 创建流程
     *
     * @param voucherId 提煤单号
     * @return
     * @author cg
     * @date 2019-09-25 09:33
     * @since 4.0
     */
    public String startFlow(BusinessEntityVO businessEntityVO,String voucherId, String businessCode) {
        Map<String, Object> querys = new HashMap<>();
        logger.info(voucherId+"-"+businessCode+"全业务流程开始启动！");
        querys.put(COMMON_USER_STR, COMMON_USER_ID);
        return baseFlowService.startActivit(businessCode, querys, new User(), businessEntityVO);
    }

    @Override
    public int endFlow(FlowActionMethodParam param){
        int k = -1;
        try {
            Task task = null;
            /**
             * 1.通过提煤单号和煤矿编码查询煤种中带的流程编码
             * */
            String flowCode = this.getBusinessCode(param.getCoalCode());
            BusinessEntityVO businessEntityVO = new BusinessEntityVO();
            businessEntityVO.setBusinessId(param.getVoucherId() + param.getCollieryId());
            businessEntityVO.setFlowCode(flowCode);
            businessEntityVO.setBusinessName("全业务流程");
            /**
             * 2.通过业务代码和流程代码查询当前流程是否存在
             * */
            ProcessInstance processInstance = isFlowExist(param.getVoucherId(), param.getCollieryId(), flowCode);
            String processInstanceID = "";
            if (processInstance != null) {
                processInstanceID = processInstance.getProcessInstanceId();
            }
            /**
             * 4.根据实例ID获取流程实例任务
             * */
            if(StringUtils.isNotEmpty(processInstanceID)){
                task = getTaskByProcessId(processInstanceID);
            }
            if(task!=null){
                Map<String, Object> variables = new HashMap<>();
                variables.put(task.getTaskDefinitionKey(), -2);
                variables.put(FlowApproveOpinion.APPROVE_MESSAGE.getValue(), "该流程已被直接结束");
                processCoreService.endProcess(task.getId(),variables, businessEntityVO);
                k = 0;
                return k ;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return k ;
    }

    /**
     * 流程主要执行方法
     * @param
     * @return
     * @author cg
     * @date 2019-10-18 17:30
     * @since 4.0
     */

    @Override
    public ResponseBean executeFlow(FlowActionMethodParam param){
        //根据当前节点查询节点表中的数据
        try {
            Task task = null;
            /**
             * 1.通过提煤单号和煤矿编码查询煤种中带的流程编码
             * */
            String flowCode = this.getBusinessCode(param.getCoalCode());
            /**
             * 2.通过业务代码和流程代码查询当前流程是否存在
             * */
            ProcessInstance processInstance = isFlowExist(param.getVoucherId(), param.getCollieryId(), flowCode);
            String processInstanceID = "";
            BusinessEntityVO businessEntityVO = new BusinessEntityVO();
            businessEntityVO.setBusinessId(param.getVoucherId() + param.getCollieryId());
            businessEntityVO.setFlowCode(flowCode);
            businessEntityVO.setBusinessName("全业务流程");
            if (processInstance != null) {
                processInstanceID = processInstance.getProcessInstanceId();
            }else{
                processInstanceID = startFlow(businessEntityVO, param.getVoucherId(), flowCode);
            }
            /**
             * 4.根据实例ID获取流程实例任务
             * */
            if(StringUtils.isNotEmpty(processInstanceID)){
                task = getTaskByProcessId(processInstanceID);
            }else{
                return new ResponseBean(CommonResultCode.FAIL.getCode(), "销售过空异常");
            }
            /**
             * 5.获取当前业务节点要执行的动作列表
             * */
            Map<String, Object> variables = new HashMap<>();
            List<ActionConfig> list = actionConfigService.getActionListByCode(flowCode, task.getTaskDefinitionKey());
            param.setFlowCode(flowCode);
            param.setTaskCode(task.getTaskDefinitionKey());
            Map<String,Object> map = checkTask(list,param,businessEntityVO,task,variables);
            if ((Boolean) map.get("isCheck")) {
                variables.put(task.getTaskDefinitionKey() + "Audit", "true");
                processCoreService.commitProcess(task.getId(), variables, null, businessEntityVO);
                return new ResponseBean(CommonResultCode.WS_SUCCESS.getCode(), CommonResultCode.WS_SUCCESS.getMsg(), map.get("checkObj"));
            }else{
                return new ResponseBean(CommonResultCode.FAIL.getCode(), "销售过空异常", null);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseBean(CommonResultCode.FAIL.getCode(), CommonResultCode.WS_SUCCESS.getMsg(), null);
        }
    }

    /**
     * 验证任务中的动作是否发生异常
     * @param list 动作列表
     * @param param 流程动作方法参数名称类
     * @param businessEntityVO 业务实例实体
     * @param task 任务实体
     * @param variables 提交的参数列表
     * @return
     * @author cg
     * @date 2019-09-25 11:48
     * @since 4.0
     */
    public Map<String, Object> checkTask(List<ActionConfig> list, FlowActionMethodParam param, BusinessEntityVO businessEntityVO, Task task, Map<String, Object> variables ) throws Exception{
        Map<String,Object> map = new HashMap<>();
        map.put("isCheck", true);
        map.put("checkObj",null);
        if (list != null && list.size() > 0) {
            ResponseBean result = new ResponseBean();
            ResponseBean resultOld = new ResponseBean();

            for (ActionConfig ac : list) {
                /**
                 * 6.反射执行动作中的方法
                 * */
                ReflectionUtils reflectionUtils = ReflectionUtils.getInstance();
                List<Object> listObject = new ArrayList<>();
                Object obj = reflectionUtils.getAutoObj(ac.getMonitorClass());
                // 验证数据正确性
                //Voucher voucher = new Voucher();
                //resultOld = (ResponseBean) ReflectionUtils.invoke(obj, "verifyVoucherExist", param.getVoucherId(), param.getCollieryId());
                //if (resultOld.getCode() != ResponseCode.WS_SUCCESS) {
                //    /**
                //     * 7.判断流程动作的执行结果，如果为错误则提交流程时给予流程审批false的结果，并发送执行错误结果给客户端
                //     * */
                //    map.put("isCheck", false);
                //    variables.put(task.getTaskDefinitionKey() + "Audit", "false");
                //    processCoreService.commitProcess(task.getId(), variables, null, businessEntityVO);
                //    break;
                //}else{
                //    voucher = (Voucher) resultOld.getData();
                //    if (StringUtils.isNotEmpty(param.getCoalCode())){
                //        Coal coal = coalService.findById(Long.parseLong(param.getCoalCode()));
                //        voucher.setCoalCode(Long.parseLong(param.getCoalCode()));
                //        voucher.setCoalName(coal.getName());
                //    }
                //    param.setVoucher(voucher);
                //}
                String[] paramList = ReflectionUtils.getParamterName(ac.getMonitorClass(), ac.getMonitorMethod());
                if(paramList!=null && paramList.length>0){
                    for(int i=0;i<paramList.length;i++){
                        Object o = ReflectionUtils.invoke(param,
                                "get"+(new StringBuilder()).append(Character.toUpperCase(paramList[i].charAt(0))).append(paramList[i].substring(1)).toString());
                        listObject.add(o!=null?o:"");
                    }
                }
                Object[] objects = listObject.toArray();
                /**
                 * 1.传入方法（Grpc方法和表单Controller方法）前将要传输的方法内的参数建立实体类。
                 * 2.每个方法（Grpc方法和表单Controller方法）按照自己的要求对实体类进行填充。
                 * 3.反射执行方法时，先获取方法的参数类型和名称用反射执行实体中的get+参数名称方法。
                 * 4.将执行的返回结果循环遍历加入到Object[]，反射再进行检验执行。
                 * */
                result = (ResponseBean) ReflectionUtils.invoke(obj, ac.getMonitorMethod(), objects);
                map.put("checkObj",result.getData());
                if (result.getCode() != CommonResultCode.WS_SUCCESS.getCode()) {
                    map.put("isCheck", false);
                    map.put("checkObj",null);
                    variables.put(task.getTaskDefinitionKey() + "Audit", "false");
                    processCoreService.commitProcess(task.getId(), variables, null, businessEntityVO);
                    break;
                }
            }
        }


        return map;
    }
}
